package common.extractText;

import lombok.Data;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 363874 fileName: E:\P201768_all_a\2022-7-1\Young people who have fallen through the Source Br J Gen Pract 2022 May 26 72 719 e413 e420[PMIDT35504728].PDF check: -37
 * 2022-12-15 14:56:30 程序全部结束，总用时：172.827933 分钟。  102751275行  41559534kb
 */
public class Change { // ㅠ⫅ㅛ╦╉╧ㅕ⊎ㅑ
    //    static String tableName = "pdf.pmid_pdf_sentence"; // 保存的表名
    static String connector = "ㅠ⫅ㅛ".toLowerCase(); // 连接符-
    static String paragraph = "ㅑ╉╧".toLowerCase(); // 段落开始符
    static String subProject = "ㅠ⨦ⱔ".toLowerCase(); // 子段落开始符
    static String lineBreak = "⬆เ⎨".toLowerCase(); // 换行符号，文本加入保存时，前面均要加上这个符号
    static String lastStr = "∱≱⬇".toLowerCase(); // 整个文档的结束符号
    static String mostStr = "⧄⬧⧁".toLowerCase(); // 最多的字符串的标识符号


    public static List<TableField> exRuijin(List<String> strList) throws IOException {
        //2024年8月13日19:58:04 此程序有问题会把中文多个句子合并到一起导致拆出来的句子入库一入一大片
        // 好像还不行 看不懂代码 直接略过了 瑞金直接强制换句子
        List<TableField> tableList = new ArrayList<>();
        String type = "";
        List<Integer> sOrder = new ArrayList<>();
        Set<String> pOrder = new HashSet<>();
        Set<String> mostStrSet = new HashSet<>();
        List<String> list = strList;
        String paragraph_name = "";
        String subProject_Name = "";
        for (String s : mostStrSet) {
//            System.out.println("mostStr: |" + s + "|");
        }
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
//            System.out.println("--" + s);
            List<String> saveList = new ArrayList<>();
            if (s.startsWith(paragraph) && !s.startsWith(paragraph + "references") && ReadTxt.fuHeParagraph(s)) {
                paragraph_name = s.replace(paragraph, "");
                continue;
            }
            if (s.startsWith(subProject) && !s.startsWith(paragraph + "references") && ReadTxt.fuHeParagraph(s)) {
                subProject_Name = s.replace(subProject, "");
                continue;
            }
            if (s.startsWith(paragraph + "references")) {
                paragraph_name = s.replace(paragraph, "");
                for (int j = i + 1; j < list.size(); j++) {
                    String t = list.get(j);
                    if (t.trim().startsWith(mostStr)) {
                        Tools.insertTable(pOrder, paragraph_name, sOrder, t.replace(mostStr, ""), subProject_Name, 10, tableList);
                        i++;
                    } else if (t.startsWith(paragraph) || t.startsWith(subProject)) {
                        break;
                    } else {
                        String references = (list.size() > i + 1) ? list.get(i + 1).trim() : "";
                        String ss = References.doReferences(references, paragraph, lineBreak, lastStr, pOrder, paragraph_name, sOrder, subProject_Name, tableList);
                        type = ss.length() > 0 ? ss : type;
                        i++;
                        break;
                    }
                }
                continue;
            }

            if (s.trim().startsWith(mostStr)) {
                saveList.add(s.replace(mostStr, ""));
            } else {
                doMatcher(s, "[A-Za-z\\])%]\\. [A-Z⬆]", 1, 1, saveList); // 1.大小写字母或右方括号或右括号，2.后面一个句号，3.再一个空格，4.再一个大写字母，方认可为一句话。为什么加"⬆"？因为换行符lineBreak是以"⬆"作为开头的，已经换行了，自然可以拆分了。
                saveList = doFigure("⬆เ⎨Figure [0-9]+\\. ", 0, 3, saveList); // 如果是图片，则新起一行，这个必须是换行符开头，但保存时要去掉换行符，若不去掉，会限入死循环。
                saveList = doFigure("⬆เ⎨Fig\\. [0-9]+ ", 0, 3, saveList); // 如果是图片，则新起一行，这个必须是换行符开头，但保存时要去掉换行符，若不去掉，会限入死循环。
                saveList = doFigure("⬆เ⎨Fig\\. [0-9]+\\. ", 0, 3, saveList); // 如果是图片，则新起一行，这个必须是换行符开头，但保存时要去掉换行符，若不去掉，会限入死循环。
                saveList = doFigure("⬆เ⎨& Figure [0-9]+\\. ", 0, 3, saveList); // 如果是图片，则新起一行，这个必须是换行符开头，但保存时要去掉换行符，若不去掉，会限入死循环。 这个前面多了一个"&"符号
                saveList = doFigure("⬆เ⎨● ", 0, 3, saveList); // 这类是行首字符，比如："● HBMECs"
                saveList = forMatcher("\\.\\[[0-9,]+\\] [A-Z]", 1, 1, saveList); // ".[1,2]"这类是句号后面是参文的标号，后面是一个空格，再后面是大写的字母。
                saveList = forMatcher("\\.[0-9]{1,3}(-|,|−)[0-9]{1,3} [A-Z]", 1, 1, saveList); // sues.87−89 More 参文的标号，先一个点，数字，连接符，数字，一个空格，最后一个大写字母。
            }
            Tools.forInsert(pOrder, paragraph_name, sOrder, saveList, subProject_Name, 10, mostStrSet, tableList);
        }
        return tableList;
    }


    public static List<TableField> ex(List<String> strList) throws IOException {
        //2024年8月13日19:58:04 此程序有问题会把中文多个句子合并到一起导致拆出来的句子入库一入一大片
        // 好像还不行 看不懂代码 直接略过了 瑞金直接强制换句子
        List<TableField> tableList = new ArrayList<>();
        String type = "";
        List<Integer> sOrder = new ArrayList<>();
        Set<String> pOrder = new HashSet<>();
        Set<String> mostStrSet = new HashSet<>();
        List<String> list = ReadTxt.readTxt(strList, mostStrSet);
        String paragraph_name = "";
        String subProject_Name = "";
        for (String s : mostStrSet) {
//            System.out.println("mostStr: |" + s + "|");
        }
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
//            System.out.println("--" + s);
            List<String> saveList = new ArrayList<>();
            if (s.startsWith(paragraph) && !s.startsWith(paragraph + "references") && ReadTxt.fuHeParagraph(s)) {
                paragraph_name = s.replace(paragraph, "");
                continue;
            }
            if (s.startsWith(subProject) && !s.startsWith(paragraph + "references") && ReadTxt.fuHeParagraph(s)) {
                subProject_Name = s.replace(subProject, "");
                continue;
            }
            if (s.startsWith(paragraph + "references")) {
                paragraph_name = s.replace(paragraph, "");
                for (int j = i + 1; j < list.size(); j++) {
                    String t = list.get(j);
                    if (t.trim().startsWith(mostStr)) {
                        Tools.insertTable(pOrder, paragraph_name, sOrder, t.replace(mostStr, ""), subProject_Name, 10, tableList);
                        i++;
                    } else if (t.startsWith(paragraph) || t.startsWith(subProject)) {
                        break;
                    } else {
                        String references = (list.size() > i + 1) ? list.get(i + 1).trim() : "";
                        String ss = References.doReferences(references, paragraph, lineBreak, lastStr, pOrder, paragraph_name, sOrder, subProject_Name, tableList);
                        type = ss.length() > 0 ? ss : type;
                        i++;
                        break;
                    }
                }
                continue;
            }

            if (s.trim().startsWith(mostStr)) {
                saveList.add(s.replace(mostStr, ""));
            } else {
                doMatcher(s, "[A-Za-z\\])%]\\. [A-Z⬆]", 1, 1, saveList); // 1.大小写字母或右方括号或右括号，2.后面一个句号，3.再一个空格，4.再一个大写字母，方认可为一句话。为什么加"⬆"？因为换行符lineBreak是以"⬆"作为开头的，已经换行了，自然可以拆分了。
                saveList = doFigure("⬆เ⎨Figure [0-9]+\\. ", 0, 3, saveList); // 如果是图片，则新起一行，这个必须是换行符开头，但保存时要去掉换行符，若不去掉，会限入死循环。
                saveList = doFigure("⬆เ⎨Fig\\. [0-9]+ ", 0, 3, saveList); // 如果是图片，则新起一行，这个必须是换行符开头，但保存时要去掉换行符，若不去掉，会限入死循环。
                saveList = doFigure("⬆เ⎨Fig\\. [0-9]+\\. ", 0, 3, saveList); // 如果是图片，则新起一行，这个必须是换行符开头，但保存时要去掉换行符，若不去掉，会限入死循环。
                saveList = doFigure("⬆เ⎨& Figure [0-9]+\\. ", 0, 3, saveList); // 如果是图片，则新起一行，这个必须是换行符开头，但保存时要去掉换行符，若不去掉，会限入死循环。 这个前面多了一个"&"符号
                saveList = doFigure("⬆เ⎨● ", 0, 3, saveList); // 这类是行首字符，比如："● HBMECs"
                saveList = forMatcher("\\.\\[[0-9,]+\\] [A-Z]", 1, 1, saveList); // ".[1,2]"这类是句号后面是参文的标号，后面是一个空格，再后面是大写的字母。
                saveList = forMatcher("\\.[0-9]{1,3}(-|,|−)[0-9]{1,3} [A-Z]", 1, 1, saveList); // sues.87−89 More 参文的标号，先一个点，数字，连接符，数字，一个空格，最后一个大写字母。
            }
            Tools.forInsert(pOrder, paragraph_name, sOrder, saveList, subProject_Name, 10, mostStrSet, tableList);
        }
        return tableList;
    }

    public static List<String> doInsert(List<String> saveList, Set<String> mostStrSet) {
        List<String> resultList = new ArrayList<>();
        for (int j = 0; j < saveList.size(); j++) {
            String str1 = saveList.get(j);
            String str2 = (saveList.size() > j + 1) ? saveList.get(j + 1).trim() : "";
            String str3 = (saveList.size() > j + 2) ? saveList.get(j + 2).trim() : "";
//            System.out.println("=== " + str1 + " str2: " + str2 + " str3: " + str3);
            boolean merge_a = getIsMerge(str1, str2, mostStrSet);
            boolean merge_b = getIsMerge(str2, str3, mostStrSet);
//            if (merge_a && str1.length() > 1 && str2.length() > 1) {
//                System.out.println("....1 " + str1);
//                System.out.println("....2 " + str2);
//            }
//            if (merge_b && str3.length() > 1 && str2.length() > 1) {
//                System.out.println("....2 " + str2);
//                System.out.println("....3 " + str3);
//            }

            if (merge_a && merge_b) { // 如果a、b都需要合并，则三条合并为一条插表，此时j++两次。
                resultList.add(str1 + " " + str2 + " " + str3);
                j = j + 2;
            } else if (merge_a) { // 如果a需要合并，b不需要合并，则合并前两条并插入，第三条不插。
                resultList.add(str1 + " " + str2);
                j++;
            } else if (merge_b) { // 如果a不需要合并，b需要合并，则第一条插表，后两条有可能与再后一条合并到一起，因此，不作处理，等下次一起处理，此时不需要j++。
                resultList.add(str1);
            } else { // 如果a、b都不需要合并，则把第一条和第二条分别插表，第三条不插。
                resultList.add(str1);
                resultList.add(str2);
                j++;
            }
        }
        return resultList;
    }

    // 如果上一句是一个左括号，下一句是一个右括号，那么这样的，不能分成两句，即需要合并的为true。如果某句是空即直接给予合并。
    public static boolean getIsMerge(String first, String next, Set<String> mostStrSet) {
        if (mostStrSet.contains(first.trim()) || mostStrSet.contains(next.trim())) {
            return false;
        }
        if (first.length() < 1 || next.length() < 1) {
            return true;
        }
        String f = first.toLowerCase().trim();
        String n = next.toLowerCase().trim();
        return isBrackets(f, n, "(", ")") || (first.endsWith(". ") && first.length() < 5 && !first.trim().contains(" ")) ||
                (first.endsWith(". ") && first.length() < 10 && !first.trim().contains(" ") && first.split("\\.").length > 2) || first.toLowerCase().endsWith(" st. ") ||
                (next.length() > 1 && next.substring(1).startsWith(".”")) || (first.endsWith("P.R. ") && next.startsWith(lineBreak + "China")) || n.startsWith(lineBreak + "com ") ||
                (first.endsWith(". ") && next.trim().endsWith("et al.") && next.length() < 20) || f.endsWith("no.") || n.length() < 5 || n.equals(lineBreak + "com") ||
                (f.endsWith("doi.") && n.startsWith(lineBreak + "org")) || (f.endsWith(".") && f.replace(lineBreak, "").length() < 3) || Pattern.compile("^[a-z]\\. ").matcher(next.trim().replace(lineBreak, "")).find();
    }

    // 如果上一句最后是左括号，下一句开始有一个右括号，则认为不能分开，应该合并，返回true。
    public static boolean isBrackets(String first, String next, String fStr, String nStr) {
        if (first.contains(fStr) && !first.substring(first.lastIndexOf(fStr)).contains(nStr)) {
            return next.contains(nStr) && !next.substring(0, next.indexOf(nStr)).contains(fStr);
        }
        return false;
    }

    public static boolean journalName(String str1, String str2, String str3, String str4) {
        str1 = str1.replace(lineBreak, "").trim();
        str2 = str2.trim();
        str3 = str3.trim();
        str4 = str4.trim();
        if (str1.endsWith(".") && str2.endsWith(".") && str3.endsWith(".") && str4.indexOf(".") > 0) {
            if (str1.contains(" ") && str1.length() > str1.lastIndexOf(" ")) {
                str1 = str1.substring(str1.lastIndexOf(" ")).trim();
            }
            str4 = str4.substring(0, str4.indexOf("."));
            if (!str2.contains(" ") && !str3.contains(" ") && !str4.contains(" ")) {
                return str1.length() < 6 && str2.length() < 6 && str3.length() < 6 && str4.length() < 6;
            }
        }
        return false;
    }

    public static List<String> forMatcher(String regular, int f_num, int s_num, List<String> inPutList) {
        List<String> result = new ArrayList<>();
        for (String s : inPutList) {
            doMatcher(s, regular, f_num, s_num, result);
        }
        return result;
    }

    public static void doMatcher(String s, String regular, int f_num, int s_num, List<String> saveList) {
        String[] split = s.split(" ");
        for (String t : split) { // 这里使用for，而不使用while，是为了防止死循环。
            Matcher matcher = Pattern.compile(regular).matcher(s);
            if (matcher.find()) {
                String group = matcher.group(0);
                String f = s.substring(0, s.indexOf(group) + group.length() - f_num);
                saveList.add(f);
                s = s.substring(s.indexOf(group) + group.length() - s_num);
            } else {
                saveList.add(s);
                break;
            }
        }
    }

    public static List<String> doFigure(String regular, int f_num, int s_num, List<String> inPutList) {
        List<String> result = new ArrayList<>();
        for (String s : inPutList) {
            String[] split = s.split(" ");
            for (String t : split) { // 这里使用for，而不使用while，是为了防止死循环。
                Matcher matcher = Pattern.compile(regular).matcher(s);
                if (matcher.find()) {
                    String group = matcher.group(0);
                    String f = s.substring(0, s.indexOf(group) - f_num);
                    result.add(f);
                    s = s.substring(s.indexOf(group) + s_num);
                } else {
                    result.add(s);
                    break;
                }
            }
        }
        return result;
    }

    public static String reStr(String str) {
        if (Pattern.compile("[0-9]ㅠ⫅ㅛ[0-9]").matcher(str).find()) { // 如果"ㅠ⫅ㅛ"前后均是数字，那么，"ㅠ⫅ㅛ"应该是一个连接符。
            str = str.replace(connector, "-");
        }
        return str.replaceAll(" +", " ").replace(connector, "").trim();
    }

    @Data // 保存的表的字段的实体类
    public static class TableField {
        private String paragraph_name = ""; // 段落的名称
        private String sub_project = ""; // 该段落内的子标题
        private String str = ""; // 句子文本
        private int code = 0; // 生成本条记录的程序
        private int paragraph = 0; // 段落的序号
        private int sentence = 0; // 句子的序号
    }

    @Data // 检查的实体类
    public static class TableCheck {
        private int strNum = 0; // 真实文本总的字符串数量
        private int differ = 0; // 真实文本与存表的数量相差的数量
        private double ratio = 0.0; // 存表误差的比例
    }


// end
}
